package pl.enigmatic.math;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;


public class ListMap<K, V> {

	private final Map<K, Vector<V>> map = new HashMap<K, Vector<V>>();

	public void clear() {
		map.clear();
	}

	public boolean containsKey(final K key) {
		return map.containsKey(key);
	}

	public boolean containsValue(final V value) {
		for (final List<V> list : map.values()) {
			if (list.contains(value)) { return true; }
		}
		return false;
	}

	public List<V> get(final K key) {
		return map.get(key);
	}

	public boolean isEmpty() {
		return map.isEmpty();
	}

	public Set<K> keySet() {
		return map.keySet();
	}

	public List<V> put(final K key, final V value) {
		final Vector<V> list;
		if (!map.containsKey(key)) {
			map.put(key, list = new Vector<V>());
		} else {
			list = map.get(key);
		}
		list.add(value);
		return list;
	}

	public void putAll(final Map<? extends K, ? extends V> m) {
		for (final Entry<? extends K, ? extends V> e : m.entrySet()) {
			put(e.getKey(), e.getValue());
		}
	}

	public List<V> remove(final K key) {
		return map.remove(key);
	}

	public int size() {
		return map.size();
	}

	public int fullSize() {
		int res = 0;
		for (final List<?> list : map.values()) {
			res += list.size();
		}
		return res;
	}

	public Iterator<V> iterator() {
		return new Iterator<V>() {

			private final int size = fullSize();
			private int next = 0;
			private final Iterator<K> keys = map.keySet().iterator();
			private List<V> list = null;
			private int index = 0;

			@Override
			public boolean hasNext() {
				return next < size;
			}

			@Override
			public V next() {
				while (list == null || index == list.size()) {
					list = map.get(keys.next());
					index = 0;
				}
				next++;
				return list.get(index++);
			}

			@Override
			public void remove() {
				list.remove(index);
			}
		};
	}
}
